package com.xyhy.core.file.utils;

import cn.hutool.core.io.FileUtil;
import com.coremedia.iso.IsoFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.mp3.MP3AudioHeader;
import org.jaudiotagger.audio.mp3.MP3File;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

public class MediaUtil {
  @SuppressWarnings("serial")
  private static Map<String, String> contentTypes = new HashMap<>() {
    {
      put("jpg", "image/jpeg");
      put("svg", "image/svg+xml");
      put("png", "image/png");
      put("gif", "image/gif");
      put("tif", "image/tiff");
      put("bmp", "image/jpeg");
      put("dwg", "image/jpeg");
      put("psd", "image/jpeg");
      put("pdf", "application/pdf");
    }
  };

  public static String getContentType(String fileType) {
    return Optional.ofNullable(fileType).map(x -> contentTypes.get(x)).orElse("application/octet-stream");
  }

  public static long getDuration(String filePath, String fileType) throws IOException {
    return getDuration(new File(filePath), fileType);
  }

  public static long getDuration(InputStream inputStream, String fileType) throws IOException {
    File tmpFile = File.createTempFile("itmg_media", "");
    try {
      FileUtil.writeFromStream(inputStream, tmpFile);
      return getDuration(tmpFile, fileType);
    } catch (Exception e) {
      return 0;
    } finally {
      tmpFile.deleteOnExit();
      if (Objects.nonNull(inputStream)) {
        inputStream.close();
      }
    }
  }

  public static long getDuration(File file, String fileType) throws IOException {
    switch (fileType) {
      case "wav":
        return getWavDuration(file).intValue();
      case "mp3":
        return getMp3Duration(file).intValue();
      case "m4a":
      case "mov":
      case "mp4":
        return getMp4Duration(file);
      default:
        return 0l;
    }
  }

  public static Float getWavDuration(File file) {
    try {
      AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
      AudioFormat format = audioInputStream.getFormat();
      long audioFileLength = file.length();
      int frameSize = format.getFrameSize();
      float frameRate = format.getFrameRate();
      float durationInSeconds = (audioFileLength / (frameSize * frameRate));
      return durationInSeconds;
    } catch (Exception e) {
      e.printStackTrace();
      return 0f;
    }
  }

  public static Float getMp3Duration(File mp3File) {
    try {
      MP3File f = (MP3File) AudioFileIO.read(mp3File);
      MP3AudioHeader audioHeader = (MP3AudioHeader) f.getAudioHeader();
      return Float.parseFloat(audioHeader.getTrackLength() + "");
    } catch (Exception e) {
      e.printStackTrace();
      return 0f;
    }
  }

  public static long getMp4Duration(File file) throws IOException {
    try (IsoFile isoFile = new IsoFile(file.getAbsolutePath())) {
      long lengthInSeconds = isoFile.getMovieBox().getMovieHeaderBox().getDuration()
              / isoFile.getMovieBox().getMovieHeaderBox().getTimescale();
      return lengthInSeconds;
    }
  }

}
